package com.kis.core.util;

import com.caucho.hessian.client.HessianProxyFactory;
import com.caucho.services.server.Service;
import com.kis.core.util.model.Hessian;
import com.kis.core.util.model.HessianBean;
import org.apache.commons.mail.DefaultAuthenticator;
import org.apache.commons.mail.Email;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.SimpleEmail;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.util.ClassUtils;

import javax.swing.text.StyledEditorKit;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Created by wongloong on 16-5-11.
 */
public class Timer {
    private DiscoveryClient discoveryClient;
    private AtomicBoolean hasStart = new AtomicBoolean(false);
    private static Map<String, Hessian> hessianMap = new ConcurrentHashMap<String, Hessian>();
    private static Timer timer;
    private HessianProxyFactory proxyFactory;
    private ThreadPoolExecutor jobExecutor;
    private ScheduledExecutorService heartbeatExecutor;


    public static Timer getInstance(DiscoveryClient discoveryClient, List<HessianBean> hessianBeanList, HessianProxyFactory proxyFactory) {
        if (null == timer) {
            timer = new Timer(discoveryClient, hessianBeanList, proxyFactory);
            timer.check();
        }
        if (null != hessianBeanList && hessianBeanList.size() > 0) {
            Hessian hessian = new Hessian();
            hessian.setServerName(hessianBeanList.get(0).getServerName());
            hessian.setHessianBeanList(hessianBeanList);
            hessian.setIpSize(hessianBeanList.size());
            if (hessianMap.isEmpty()) {
                hessianMap.put(hessian.getServerName(), hessian);
            } else {
                if (hessianMap.containsKey(hessian.getServerName())) {
                    Hessian oldHessian = hessianMap.get(hessian.getServerName());
                    oldHessian.getHessianBeanList().addAll(hessian.getHessianBeanList());
                    hessianMap.put(hessian.getServerName(), oldHessian);
                } else {
                    hessianMap.put(hessian.getServerName(), hessian);
                }
            }
        }
        return timer;
    }

    public void check() {
        if (!hasStart.get()) {
            heartbeatExecutor = Executors.newSingleThreadScheduledExecutor();
            ArrayBlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<Runnable>(
                    1000);
            jobExecutor = new ThreadPoolExecutor(5, 30, 30 * 1000,
                    TimeUnit.MILLISECONDS, workQueue);
            start();
            hasStart.set(true);
        }
    }

    public void start() {
        heartbeatExecutor.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("running scan server");
                    boolean changed = false;
                    for (Map.Entry<String, Hessian> map : hessianMap.entrySet()) {
                        String serverName = map.getKey();
                        Hessian hessian = map.getValue();
                        List<ServiceInstance> serviceInstances = discoveryClient.getInstances(serverName);
                        //缓存的hessianProxy列表
                        List<HessianBean> hessianBeanList = hessian.getHessianBeanList();
                        if (serviceInstances.size() > 0) {//缓存
                            if (hessian.getIpSize() > serviceInstances.size()) {//当前应用服务总数大于服务中心服务总数,说明有挂掉的服务器。逐各进行心跳检测并删除
                                Iterator<HessianBean> iterator = hessianBeanList.iterator();
                                while (iterator.hasNext()) {
                                    HessianBean hessianBean = iterator.next();
                                    try {
                                        if (!isAlive(hessianBean.getUri())) {

                                        }
                                    } catch (IOException e) {
                                        changed = true;
                                        iterator.remove();
                                    }
                                }
                                hessian.setHessianBeanList(hessianBeanList);
                                hessian.setIpSize(hessian.getIpSize() - 1);
                            }
                        }
                        //进行逐一校验,看是否有未加入到此应用的服务
                        for (ServiceInstance serviceInstance : discoveryClient.getInstances(serverName)) {
                            boolean hasNew = true;
                            for (HessianBean hessianBean : hessianBeanList) {
                                if (serviceInstance.getUri().toString().equalsIgnoreCase(hessianBean.getUri())) {
                                    hasNew = false;
                                    break;
                                }
                            }
                            if (hasNew) {
                                changed = true;
                                if (!hessianBeanList.isEmpty() && isAlive(serviceInstance.getUri().toString())) {
                                    List<HessianBean> newHbs = new ArrayList<HessianBean>();
                                    for (HessianBean hb : hessian.getHessianBeanList()) {
                                        Object hessianService = proxyFactory.create(hb.getHessianInterface(), serviceInstance.getUri() + "/" + hb.getAccessPath(), ClassUtils.getDefaultClassLoader());
                                        HessianBean newHb = new HessianBean();
                                        newHb.setAccessPath(hb.getAccessPath());
                                        newHb.setPort(serviceInstance.getPort());
                                        newHb.setHessian(hessianService);
                                        newHb.setServerName(serverName);
                                        newHb.setUri(serviceInstance.getUri().toString());
                                        newHbs.add(newHb);
                                        System.out.println("添加新的服务");
                                    }
                                    hessian.getHessianBeanList().addAll(newHbs);
                                    hessian.setIpSize(hessian.getIpSize()+1);
                                    hessianMap.put(serverName, hessian);
                                }
                            }
                        }
                    }
                    if (changed) {
                        HessianBalance.assemableHessianProxy(hessianMap);
                    }
                } catch (Exception t) {
                    if (t instanceof IOException) {
                        sendEmail(t.getMessage());
                    }
                    t.printStackTrace();
                }
            }
        }, 30, 30, TimeUnit.SECONDS);
    }

    public boolean isAlive(String url) throws IOException {
        boolean result = true;
        URL targetUrl = new URL(url);
        URLConnection connection = targetUrl.openConnection();
        HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
        httpURLConnection.setConnectTimeout(1500);
        httpURLConnection.setReadTimeout(1000);
        httpURLConnection.connect();
        Integer code = httpURLConnection.getResponseCode();
        if (!(code.toString().startsWith("2") || code.toString().startsWith("4"))) {
            result = false;
        }
        return result;
    }

    private void sendEmail(String msg) {
        try {
            Email email = new SimpleEmail();
            email.setHostName("smtp.ym.163.com");
            email.setAuthenticator(new DefaultAuthenticator("sender@find2i.com", "ocqBjoWXAE"));
            email.setSSLOnConnect(true);
            email.setFrom("sender@find2i.com");
            email.setSubject("服务器停止运行");
            email.setMsg(msg);
            email.addTo("67180179@qq.com");
            email.send();
        } catch (EmailException e) {
            e.printStackTrace();
        }
    }

    private Timer(DiscoveryClient discoveryClient, List<HessianBean> hessianBeen, HessianProxyFactory proxyFactory) {
        this.discoveryClient = discoveryClient;
        this.proxyFactory = proxyFactory;
    }

    public static Map<String, Hessian> getHessianMap() {
        return hessianMap;
    }
}
